<template>
  <div
    class="edit-wrapper"
    @click.stop="onItemClick(id)"
    :class="{ active: active }"
    :style="style"
    ref="editWrapper"
    @mousedown="startMove($event, id)"
    :data-component-id="id"
  >
    <slot></slot>
    <div class="resizers">
      <div
        class="resizer top-left"
        @mousedown.stop="startResize($event, 'top-left')"
      ></div>
      <div
        class="resizer top-right"
        @mousedown.stop="startResize($event, 'top-right')"
      ></div>
      <div
        class="resizer bottom-left"
        @mousedown.stop="startResize($event, 'bottom-left')"
      ></div>
      <div
        class="resizer bottom-right"
        @mousedown.stop="startResize($event, 'bottom-right')"
      ></div>
    </div>
    <div class="component-remove" v-if="active" @click="deleteItem">❌</div>
  </div>
</template>

<script setup lang="ts">
import {
  defineProps,
  defineEmits,
  withDefaults,
  computed,
  ref,
  nextTick,
} from "vue";
import { pick } from "lodash-es";
import { AllComponentProps } from "@/defaultProps";
type ResizeDirection =
  | "top-left"
  | "top-right"
  | "bottom-left"
  | "bottom-right";
interface OriginalPositions {
  left: number;
  right: number;
  top: number;
  bottom: number;
}
const props = withDefaults(
  defineProps<{
    id: string;
    active: boolean;
    props: Partial<AllComponentProps>;
  }>(),
  {
    active: false,
  }
);
const editWrapper = ref<null | HTMLElement>(null);

const emits = defineEmits(["set-active", "deleteItem", "updatePosition"]);

const style = computed(() => {
  return pick(props.props, ["left", "top", "width", "height", "position"]);
});

const onItemClick = (id: string) => {
  emits("set-active", id);
};

const deleteItem = () => {
  emits("deleteItem", props.id);
};

const gap = {
  x: 0,
  y: 0,
};
let isMoving = false;
const calculatePosition = (e: MouseEvent) => {
  const container = document.getElementById("canvas-ares") as HTMLElement;
  // console.log(container.offsetLeft, container.getBoundingClientRect().left);
  const { clientX, clientY } = e;
  const left = clientX - gap.x - container.offsetLeft;
  const top = clientY - gap.y - container.offsetTop + container.scrollTop;
  return { left, top };
};
const startMove = (e: MouseEvent, id: string) => {
  // console.log("startMove");
  emits("set-active", id);
  const currentElement = editWrapper.value;
  if (currentElement) {
    const { left, top } = currentElement.getBoundingClientRect();
    gap.x = e.clientX - left;
    gap.y = e.clientY - top;
  }
  const handleMove = (e: MouseEvent) => {
    const { left, top } = calculatePosition(e);
    // console.log(left,top);
    if (currentElement) {
      currentElement.style.left = left + "px";
      currentElement.style.top = top + "px";
      isMoving = true;
    }
  };

  const handleMouseUp = (e: MouseEvent) => {
    // console.log("handleMouseUp", e.target);
    document.removeEventListener("mousemove", handleMove);
    const { left, top } = calculatePosition(e);
    if (isMoving) {
      emits("updatePosition", { id: props.id, left, top });
      isMoving = false;
    }
    nextTick(() => {
      document.removeEventListener("mouseup", handleMouseUp);
    });
  };
  // 注册新的事件监听器
  document.addEventListener("mousemove", handleMove);
  document.addEventListener("mouseup", handleMouseUp);
};

const caculateSize = (
  direction: ResizeDirection,
  e: MouseEvent,
  positions: OriginalPositions
) => {
  const { left, right, top, bottom } = positions;
  const { pageX, pageY } = e;
  const container = document.getElementById("canvas-ares") as HTMLElement;
  const rightWidth = pageX - left;
  const bottomHeight = pageY - top;
  const leftWidth = right - pageX;
  const topHeight = bottom - pageY;
  const leftOffset = pageX - container.offsetLeft;
  const topOffset = pageY - container.offsetTop + container.scrollTop; //考虑到了滚动的情况
  switch (direction) {
    case "top-left":
      return {
        width: leftWidth,
        height: topHeight,
        top: topOffset,
        left: leftOffset,
      };
    case "top-right":
      return {
        width: rightWidth,
        height: topHeight,
        top: topOffset,
      };
    case "bottom-left":
      return {
        width: leftWidth,
        height: bottomHeight,
        left: leftOffset,
      };
    case "bottom-right":
      return {
        width: rightWidth,
        height: bottomHeight,
      };
    default:
      break;
  }
};

let size: any;
const startResize = (event: MouseEvent, direction: ResizeDirection) => {
  const currentElement = editWrapper.value as HTMLElement;
  // const moveElement = moveWrapper.value as HTMLElement
  // get the component element
  // const currentComponent = moveElement.firstElementChild as HTMLElement
  const resizeElements = [currentElement]; //, currentComponent]
  const { left, right, top, bottom } = currentElement.getBoundingClientRect();
  const handleMove = (e: MouseEvent) => {
    if (currentElement) {
      size = caculateSize(direction, e, { left, right, top, bottom });
      resizeElements.forEach((element) => {
        const { style } = element;
        if (size) {
          if (size.left) {
            style.left = size.left + "px";
          }
          if (size.top) {
            style.top = size.top + "px";
          }
          style.width = size.width + "px";
          style.height = size.height + "px";
          // context.emit('update-position', { ...size, id: props.id })
        }
      });
    }
  };
  const handleMouseUp = () => {
    document.removeEventListener("mousemove", handleMove);
    emits("updatePosition", { ...size, id: props.id });
    nextTick(() => {
      document.removeEventListener("mouseup", handleMouseUp);
    });
  };
  document.addEventListener("mousemove", handleMove);
  document.addEventListener("mouseup", handleMouseUp);
};
</script>

<style scoped lang="less">
.edit-wrapper {
  padding: 0px;
  cursor: pointer;
  border: 1px solid transparent;
  user-select: none;
  /* transition: all 0.3s ease-out; */
  position: relative;
  box-sizing: content-box;
}

.edit-wrapper:hover {
  border: 1px dashed #ccc;
}

.edit-wrapper.active {
  border: 1px dashed #1890ff;
  user-select: none;
  /* z-index: 100; */
}

.edit-wrapper.active .component-remove {
  opacity: 1;
}
.component-remove {
  font-size: 10px;
  position: absolute;
  bottom: 5px;
  right: 5px;
  cursor: pointer;
  opacity: 0;
}

.edit-wrapper ::v-deep .remove-position {
  position: static !important;
  width: 100% !important;
  height: 100% !important;
}

.edit-wrapper .resizers {
  display: none;
}

.edit-wrapper.active .resizers {
  display: block;

  .resizer {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: #fff;
    position: absolute;
    border: 2px solid #1890ff;

    &.top-left {
      top: -5px;
      left: -5px;
      cursor: nw-resize;
    }
    &.top-right {
      top: -5px;
      right: -5px;
      cursor: ne-resize;
    }
    &.bottom-left {
      bottom: -5px;
      left: -5px;
      cursor: sw-resize;
    }
    &.bottom-right {
      bottom: -5px;
      right: -5px;
      cursor: se-resize;
    }
  }
}
</style>
